/**
 * @class   wosh::Method
 * @brief   Holds generic method information, required arguments and its
 *          (imlementation) pointer.
 *
 *
 *
 * \code
	MethodT<const Request*, Response*>* mmPropertyList = new MethodT<const Request*, Response*>( _METHOD_ListProperties );
	mmPropertyList->setMethod( this, (MethodT<const Request*, Response*>::MethodTPtr)&BundleGeneric::mmDoPropertyList );
	mmPropertyList->getPermission().setMask( Permission::RX );
	Methods.registerMethod(mmPropertyList);

	MethodRequest* mmMethodList = new MethodRequest( _METHOD_ListMethods );
	mmMethodList->setMethod( this, (MethodRequestPtr)&BundleGeneric::mmDoMethodList );
	mmMethodList->getPermission().setMask( Permission::RX );
	Methods.registerMethod(mmMethodList);
 * \endcode
 *
 *
 ****************************************************************************
 * @version $Id: Method.h 2827 2010-08-02 11:01:48Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR MethodS;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef __WOSH_Core_Method_H__
 #define __WOSH_Core_Method_H__

 #include <woshDefs.h>
 #include <core/Variant.h>
 #include <core/Mutex.h>
 #include <core/URI.h>
 #include <core/Permission.h>
 #include <core/MethodArguments.h>

 #include <vector>
 #include <map> //MethodCollector

 #if defined(_MSC_VER)
  // win32: http://social.msdn.microsoft.com/forums/en-US/vclanguage/thread/05a59a5f-1370-418f-9460-e4dd49d19ddf/
  //        http://msdn.microsoft.com/en-us/library/ms864492.aspx
  // especially for wince!
  #pragma pointers_to_members( full_generality, virtual_inheritance )
 #endif


namespace wosh {

typedef int WRESULT_METHOD;

 #define WRET_METHOD_VALID			0     /* no errors found */
 #define WRET_METHOD_ERR_CONTENT	1     /* error: illegal content */
 #define WRET_METHOD_ERR_ARGCOUNT	2     /* error: required parameter(s) count */
 #define WRET_METHOD_ERR_UNKNOWN	4     /* unknown error */
 #define WRET_METHOD_ERR_ARGTYPE	16    /* illegal parameter type, result is 16*paramID */


class MethodRunner {
	public:
		virtual ~MethodRunner() { }

 };

class MethodCollector;
class Message;
template <class T> class DataFieldCollector;


class Method : public virtual IReflection
 {
	WOSH_CLASSNAME(wosh::Method)
	WOSH_CLASS_ABSTRACT(true)

	public:
		/**
		 * @brief  Default constructor. Initialize its name.
		 * @param name [in] the name of the method. no spaces and special characters
		 */
		Method( const std::string& name );
		/**
		 * @brief  Common constructor. Initialize its name and description.
		 * @param name [in] the name of the method. no spaces and special characters
		 * @param description [in] short optional description of the method
		 * @param perm [in] permission object to be associated with the method
		 */
		Method( const std::string& name, const std::string& description, const Permission& perm = Method::defaultPermission );
		/**
		 * @brief  Copy constructor.
		 * @param m [in] the method to be copied
		 */
		Method( const Method& m );
		/**
		 * @brief  Empty destructor. Eventually unregister the method when set as global.
		 */
		virtual ~Method();

	public:
		void registerGlobal( const URI& ownerUri );
		void unRegisterGlobal();

//@}
/** @name Execution and Validation
 * @{
 ******************************************************************************/
	public:
		virtual Message* exec( const Message* request ) = 0;

//		virtual short compare(const Method& other) const = 0;

		virtual bool isLinkedFunction() const = 0;
		virtual bool isLinkedParent() const = 0;

//@}
/** @name Getters
 * @{
 ******************************************************************************/
	public:
		/**
		 * @brief  Get the method name
		 * @return return (constant) reference to the method name
		 * @see    setName()
		 */
		inline const std::string& getName() const						{ return this->name; }
		inline std::string& getName()									{ return this->name; }

		/**
		 * @brief  Get the method description
		 * @return return (constant) reference to the method description
		 * @see    setDescription()
		 */
		inline const std::string& getDescription() const				{ return this->description; }
		inline std::string& getDescription()							{ return this->description; }

		/**
		 * @brief  Get the method permission
		 * @return return (constant) reference to the method permission
		 * @see    setPermission()
		 */
		inline const Permission& getPermission() const			{ return this->permission; }
		inline Permission& getPermission()						{ return this->permission; }

		inline const MethodArguments& getArguments() const 		{ return this->arguments; }
		inline MethodArguments& getArguments()					{ return this->arguments; }

		MethodArgument& getArgument( unsigned int index )			{ return this->arguments.get(index); }

		std::string toStringUnixStyle() const;

		static const char* getGenericErrorDescription( WRESULT retcode );

		static DataFieldCollector<Method>* getDataFields();

//@}
/** @name Setters
 * @{
 ******************************************************************************/
	public:
		/**
		 * @brief  Set the method name
		 * @param [in] value literal string representing the method name
		 * @see    getName()
		 */
		virtual void setName( const std::string& value )				{ this->name = value; }
		/**
		 * @brief  Set the method description
		 * @param [in] value literal string representing the method description
		 * @see    getName()
		 */
		virtual void setDescription( const std::string& value )			{ this->description = value; }

		/**
		 * @brief  Set the method permission
		 * @param [in] perm method permission to be set
		 * @see    setPermission()
		 */
		virtual void setPermission( const Permission& perm )		{ this->permission = perm; }

		virtual void setPermission( const Permission& value, short overwrite_mode, bool when_empty ) {
			this->permission.inherit(value, overwrite_mode, when_empty);
		 }

		virtual void setArguments( const MethodArguments& value )	{ this->arguments = value; }



		inline void transactionBeginRead() const	{ this->mux.lockForRead(); }
		inline void transactionBeginWrite() const	{ this->mux.lockForWrite(); }
		inline void transactionEnd() const			{ this->mux.unLock(); }

//@}
/** @name Operators Overloading
 * @{
 ******************************************************************************/
	public:
		virtual bool operator==(const Method&) const {
			return false; //(compare(other) == 0);
		 }
		virtual bool operator!=(const Method &other) const		{ return !(*this == other);  }
//@}

	protected:
		virtual void clear();

	protected:
		std::string name;					///< function name (unique within a service)
		std::string description;			///< brief description
		Permission permission;		///< access permission
		MethodArguments arguments;	///< argument def
		mutable MutexRW mux;

	protected:
		bool global;
		URI ownerReference;

		friend class wosh::MethodCollector;

	public:	
		static const Permission defaultPermission;



}; // class def




//////////////////////////////////////////////////////////////////////////////////////////////////////////////

class MethodCollector  {
	public:
		MethodCollector() { }
		virtual ~MethodCollector() { }

	public:
		static int getList( std::vector<std::string>& output_list );
		static int gets( std::vector<Method*>& results, const std::string method_name, bool global_only = false );
		static Method* get( const std::string method_name );

		static long exists( const Method* method );
		static long exists( const std::string method_name );

	protected:
		static std::multimap<std::string, Method*> Methods;
		static MutexRW MethodsMux;
		friend class wosh::Method;

}; // class def


}; // namespace wosh

#endif //__WOSH_Core_Method_H__
